﻿using System;
using System.Linq;
using System.ServiceProcess;
using System.Windows.Forms;
using mki.Backup.GUI.Dialogs;
using mki.Backup.GUI.Helper;
using mki.Backup.GUI.Properties;
using mki.Backup.Helper;
using mki.Backup.GUI.Enumerations;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using System.Net.Configuration;
using mki.Backup.Objects;
using mki.Backup.Objects.ValidationObjects;

namespace mki.Backup.GUI
{
	internal class MainFormController
	{
		#region Fields (5)

		// ReadOnly Fields (2) 

		private readonly ContextMenuStrip contextMenuStrip = new ContextMenuStrip();

		private readonly ServiceController serviceController;
		// Fields (3) 

		private BackupConfiguration backupConfig;

		private Configuration config;

		private SmtpSection smtpConfig;

		private Boolean showSaveHint = true;

		#endregion Fields

		#region Constructors (1)

		/// <summary>
		/// Initializes a new instance of the <see cref="MainFormController"/> class.
		/// </summary>
		public MainFormController()
		{
			this.MainForm = new MainForm { ErrorGridVisible = false };
			this.MainForm.JobTreeView.AfterSelect += this.treeViewAfterSelect;
			this.MainForm.JobTreeView.MouseDown += this.jobTreeViewMouseDown;
			this.MainForm.JobTreeView.NodeMouseClick += (s, e) => e.CreateContextMenu(this.contextMenuStrip);
			this.MainForm.JobTreeView.LoadImages();
			this.MainForm.JobTreeView.ContextMenuStrip = this.contextMenuStrip;
			this.MainForm.ButtonClick = this.buttonClick;
			this.contextMenuStrip.ItemClicked += (s, e) => this.buttonClick(s, (ButtonAction)e.ClickedItem.Tag);
			this.loadConfig();

			try
			{
				this.serviceController = new ServiceController("Backup Service");
				if (String.IsNullOrWhiteSpace(this.serviceController.DisplayName)) { this.serviceController = null; }
			}
			catch (Exception ex)
			{
				Logging.WriteCritical("Service not found: {0}\n{1}", ex.Message, ex.StackTrace);
				this.serviceController = null;
			}

			this.showServiceState();
		}

		#endregion Constructors

		#region Properties (1)

		// Public Properties (1) 

		public MainForm MainForm { get; set; }

		#endregion Properties

		#region Methods (11)

		// Private Static Methods (3) 

		/// <summary>
		/// Clears the log files.
		/// </summary>
		private static void clearLogFiles()
		{
			try
			{
				var regex = new Regex(@"[A-Za-z_\.]*(\d{8}_\d{4}|\d{4}-\d{2}-\d{2}.\d{1}).log", RegexOptions.IgnoreCase);
				var files = Directory.GetFiles(Logging.LogPath, "*.log");

				foreach (var file in files)
				{
					var fileInfo = new FileInfo(file);
					if (regex.IsMatch(fileInfo.Name)) { fileInfo.Delete(); }
				}
				Logging.WriteVerbose("cleaned up logfiles");
			}
			catch (Exception ex)
			{
				MessageBoxHandler.ShowErrorMessageBox("Error while deleting logfiles: {0}\n{1}", ex.Message, ex.StackTrace);
			}
		}

		/// <summary>
		/// Opens the log file.
		/// </summary>
		/// <param name="action">The action.</param>
		private static void openLogFile(ButtonAction action)
		{
			try
			{
				var logFile = Logging.LogFilePath;
				if (action == ButtonAction.OpenServiceLogFile) { logFile = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), Logging.LogPath, "Backup.Service.log"); }

				if (!File.Exists(logFile)) { throw new FileNotFoundException(String.Format("The logfile '{0}' could not be found!", logFile)); }

				var process = new Process { StartInfo = new ProcessStartInfo { FileName = logFile } };
				process.Start();
			}
			catch (Exception ex)
			{
				MessageBoxHandler.ShowErrorMessageBox("Error while opening log: {0}\n{1}", ex.Message, ex.StackTrace);
			}
		}

		/// <summary>
		/// Opens the link.
		/// </summary>
		/// <param name="url">The URL.</param>
		private static void openUrl(String url)
		{
			try { Process.Start(url); }
			catch (Exception ex)
			{
				if (ex.GetType().ToString() != "System.ComponentModel.Win32Exception")
				{
					try { Process.Start(new ProcessStartInfo("IExplore.exe", url)); }
					catch (Exception ieEx)
					{
						Logging.WriteCritical("Cannot open URL '{0}': {1}\n{2}", url, ieEx.Message, ieEx.StackTrace);
					}
				}
			}
		}
		// Private Methods (8) 

		/// <summary>
		/// Buttons the click.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="action">The action.</param>
		private void buttonClick(Object sender, ButtonAction action)
		{
			if (this.MainForm == null) { return; }

			switch (action)
			{
				case ButtonAction.AddJob:
					var backupJob = new BackupJobElement { Name = Resources.NewElementName, AttachLogFile = true, ContinueOnError = false, Enabled = true, StartJobAt = String.Format("{0}:00", DateTime.Now.Hour) };
					this.backupConfig.BackupJobsCollection.Add(backupJob);
					this.MainForm.JobTreeView.Nodes.Add(JobLoadExtension.CreateTreeNode(Resources.NewElementName, "job_enabled", backupJob));
					break;

				case ButtonAction.AddDBBackupJob:
					var backupSection = new DBBackupSection();
					this.backupConfig.BackupJobsCollection[((BackupJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).Name].DBBackupJobsCollection = backupSection;
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(Resources.NodeDBBackupJobs, "database_save", backupSection));
					break;

				case ButtonAction.AddRunProcessJob:
					var runProcessSection = new RunProcessSection();
					this.backupConfig.BackupJobsCollection[((BackupJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).Name].RunProcessJobsCollection = runProcessSection;
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(Resources.NodeRunProcessJobs, "cog", runProcessSection));
					break;

				case ButtonAction.AddZIPJob:
					var zipJobSection = new ZipJobSection();
					this.backupConfig.BackupJobsCollection[((BackupJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).Name].ZipJobsCollection = zipJobSection;
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(Resources.NodeZipJobs, "compress", zipJobSection));
					break;

				case ButtonAction.AddFTPJob:
					var ftpJobSection = new FTPJobSection();
					this.backupConfig.BackupJobsCollection[((BackupJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).Name].FTPJobsCollection = ftpJobSection;
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(Resources.NodeFTPJobs, "drive_network", ftpJobSection));
					break;

				case ButtonAction.AddDatabaseBackup:
					var backupElement = new DBBackupElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((DBBackupSection)this.MainForm.JobTreeView.SelectedNode.Tag).Add(backupElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(backupElement.Name, "database", backupElement));
					break;

				case ButtonAction.AddProcess:
					var processElement = new RunProcessElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((RunProcessSection)this.MainForm.JobTreeView.SelectedNode.Tag).Add(processElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(processElement.Name, "cog_go", processElement));
					break;

				case ButtonAction.AddZIP:
					var zipElement = new ZipJobElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((ZipJobSection)this.MainForm.JobTreeView.SelectedNode.Tag).Add(zipElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(zipElement.Name, "folder_page_white", zipElement));
					break;

				case ButtonAction.AddFTP:
					var ftpElement = new FTPJobElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((FTPJobSection)this.MainForm.JobTreeView.SelectedNode.Tag).Add(ftpElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(ftpElement.Name, "package", ftpElement));
					break;

				case ButtonAction.AddFTPFileUpload:
					var ftpFileUploadElement = new FTPAddElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((FTPJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).AddFileCollection.Add(ftpFileUploadElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(ftpFileUploadElement.Name, "page_white_get", ftpFileUploadElement));
					break;

				case ButtonAction.AddFTPDeleteAction:
					var ftpFileDeleteElement = new FTPDeleteElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((FTPJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).DeleteFileCollection.Add(ftpFileDeleteElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(ftpFileDeleteElement.Name, "page_white_delete", ftpFileDeleteElement));
					break;

				case ButtonAction.AddZipFile:
					var zipAddFileElement = new ZipAddFileElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((ZipJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).AddFileCollection.Add(zipAddFileElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(zipAddFileElement.Name, "page_white_zip", zipAddFileElement));
					break;

				case ButtonAction.AddZipFolder:
					var zipAddFolderElement = new ZipAddFolderElement { Name = String.Format("{0} {1}", Resources.NewElementName, this.MainForm.JobTreeView.SelectedNode.GetNodeCount(false) + 1) };
					((ZipJobElement)this.MainForm.JobTreeView.SelectedNode.Tag).AddFolderCollection.Add(zipAddFolderElement);
					this.MainForm.JobTreeView.SelectedNode.Nodes.Add(JobLoadExtension.CreateTreeNode(zipAddFolderElement.Name, "folder", zipAddFolderElement));
					break;

				case ButtonAction.Remove:
					var configNode = this.MainForm.JobTreeView.SelectedNode.Tag;
					if (configNode is BackupJobElement) { this.backupConfig.BackupJobsCollection.Remove(configNode as BackupJobElement); }
					if (configNode is DBBackupElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.DBBackupJobsCollection.Remove(configNode as DBBackupElement)); }
					if (configNode is RunProcessElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.RunProcessJobsCollection.Remove(configNode as RunProcessElement)); }
					if (configNode is ZipJobElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.ZipJobsCollection.Remove(configNode as ZipJobElement)); }
					if (configNode is FTPJobElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.FTPJobsCollection.Remove(configNode as FTPJobElement)); }
					if (configNode is FTPAddElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.FTPJobsCollection.Cast<FTPJobElement>().ToList().ForEach(si => si.AddFileCollection.Remove(configNode as FTPAddElement))); }
					if (configNode is FTPDeleteElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.ZipJobsCollection.Cast<FTPJobElement>().ToList().ForEach(si => si.DeleteFileCollection.Remove(configNode as FTPDeleteElement))); }
					if (configNode is ZipAddFileElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.ZipJobsCollection.Cast<ZipJobElement>().ToList().ForEach(si => si.AddFileCollection.Remove(configNode as ZipAddFileElement))); }
					if (configNode is ZipAddFolderElement) { this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>().ToList().ForEach(i => i.ZipJobsCollection.Cast<ZipJobElement>().ToList().ForEach(si => si.AddFolderCollection.Remove(configNode as ZipAddFolderElement))); }

					// and remove from treeview
					this.MainForm.JobTreeView.SelectedNode.Remove();
					break;

				case ButtonAction.Save:
					this.saveConfiguration();
					break;

				case ButtonAction.ToggleService:
					this.toggleService();
					this.showServiceState();
					break;

				case ButtonAction.Exit:
					this.MainForm.Close();
					break;

				case ButtonAction.About:
					var aboutBox = new AboutBox();
					if (aboutBox.ShowDialog() == DialogResult.OK) { aboutBox.Close(); }
					break;

				case ButtonAction.RowSelected:
					var validationErrorItem = sender as ValidationErrorItem;
					if (validationErrorItem != null)
					{
						var nodes = this.MainForm.JobTreeView.Nodes.Cast<TreeNode>().Descendants(c => c.Nodes.Cast<TreeNode>());
						this.MainForm.JobTreeView.SelectedNode = nodes.Where(n => n.Tag == validationErrorItem.Item).FirstOrDefault();
					}
					break;

				case ButtonAction.OpenGUILogFile:
				case ButtonAction.OpenServiceLogFile:
					openLogFile(action);
					break;

				case ButtonAction.ClearLogFiles:
					clearLogFiles();
					break;

				case ButtonAction.SMTPSettings:
					this.openMailServerSettings();
					break;

				case ButtonAction.Help:
					openUrl(Resources.HelpUri);
					break;

				default:
					throw new NotImplementedException("This action is not supported yet");
			}

			// expand current node
			if (sender is ContextMenuStrip)
			{
				this.MainForm.JobTreeView.SelectedNode = this.MainForm.JobTreeView.SelectedNode.LastNode;
				this.MainForm.JobTreeView.SelectedNode.Expand();
				// and clear up
				this.contextMenuStrip.Items.Clear();
			}
		}

		/// <summary>
		/// Jobs the tree view mouse down.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
		private void jobTreeViewMouseDown(object sender, MouseEventArgs e)
		{
			var treeView = sender as TreeView;
			if (treeView == null) { return; }

			if (e.Button == MouseButtons.Right)
			{
				treeView.SelectedNode = treeView.GetNodeAt(e.X, e.Y);
				if (treeView.SelectedNode == null)
				{
					treeView.CreateContextMenu(this.contextMenuStrip);
				}
			}
		}

		/// <summary>
		/// Loads the backup config.
		/// </summary>
		private void loadConfig()
		{
			if (this.MainForm == null) { return; }

			this.MainForm.JobTreeView.SuspendLayout();

			// remember current node
			var currentNodePath = this.MainForm.JobTreeView.SelectedNode != null ? this.MainForm.JobTreeView.SelectedNode.FullPath : String.Empty;
			this.MainForm.JobTreeView.Nodes.Clear();

			try
			{
				this.config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = "mki.Backup.GUI.exe.config" }, ConfigurationUserLevel.None);
				this.backupConfig = this.config.GetSection("backupConfiguration") as BackupConfiguration;
				this.smtpConfig = this.config.GetSectionGroup("system.net").SectionGroups.Get("mailSettings").Sections.Get("smtp") as SmtpSection;
			}
			catch (Exception ex)
			{
				MessageBoxHandler.ShowErrorMessageBox(Resources.ErrorLoadingConfiguration);
				Logging.WriteError("while loading configuration: {0}\n{1}", ex.Message, ex.StackTrace);
			}

			// list found jobs?
			if (this.backupConfig == null) { return; }

			foreach (var backupJob in this.backupConfig.BackupJobsCollection.Cast<BackupJobElement>())
			{
				var rootNode = JobLoadExtension.CreateTreeNode(backupJob.Name, backupJob.Enabled ? "job_enabled" : "job_disabled", backupJob);

				// db backup jobs
				if (backupJob.DBBackupJobsCollection.Count > 0) { rootNode.Nodes.Add(backupJob.LoadDBBackupJobs()); }

				// run process jobs
				if (backupJob.RunProcessJobsCollection.Count > 0) { rootNode.Nodes.Add(backupJob.LoadRunProcessJobs()); }

				// zip jobs
				if (backupJob.ZipJobsCollection.Count > 0) { rootNode.Nodes.Add(backupJob.LoadZipJobs()); }

				// ftp jobs
				if (backupJob.FTPJobsCollection.Count > 0) { rootNode.Nodes.Add(backupJob.LoadFTPJobs()); }

				// add to root node
				this.MainForm.JobTreeView.Nodes.Add(rootNode);
			}

			this.MainForm.JobTreeView.ExpandAll();

			// reselect node
			if (!String.IsNullOrWhiteSpace(currentNodePath))
			{
				var nodes = this.MainForm.JobTreeView.Nodes.Cast<TreeNode>().Descendants(c => c.Nodes.Cast<TreeNode>());
				this.MainForm.JobTreeView.SelectedNode = nodes.Where(n => n.FullPath == currentNodePath).FirstOrDefault();
				if (this.MainForm.JobTreeView.SelectedNode != null) { this.MainForm.JobTreeView.Select(); }
			}
			else
			{	// select first node
				this.MainForm.JobTreeView.SelectedNode = this.MainForm.JobTreeView.Nodes.Cast<TreeNode>().FirstOrDefault();
			}

			this.MainForm.JobTreeView.ResumeLayout();

			Logging.WriteVerbose("configuration was loaded successfully");
		}

		/// <summary>
		/// Opens the mail server settings.
		/// </summary>
		private void openMailServerSettings()
		{
			if (!this.saveConfiguration()) { return; }

			var mailServerSettings = new MailSettingsForm
										{
											MailServerSettings = this.smtpConfig,
											StartPosition = FormStartPosition.CenterParent
										};
			if (mailServerSettings.ShowDialog() == DialogResult.OK)
			{
				// copy values
				this.smtpConfig.From = mailServerSettings.MailServerSettings.From;
				this.smtpConfig.Network.Host = mailServerSettings.MailServerSettings.Network.Host;
				this.smtpConfig.Network.Port = mailServerSettings.MailServerSettings.Network.Port;
				this.smtpConfig.Network.UserName = mailServerSettings.MailServerSettings.Network.UserName;
				this.smtpConfig.Network.Password = mailServerSettings.MailServerSettings.Network.Password;
				// save
				this.smtpConfig.CurrentConfiguration.Save(ConfigurationSaveMode.Modified);
				mailServerSettings.Close();

				// and reload config -> in this case changes on backup config gets lost but hmm we need to do it ^^
				this.loadConfig();
			}
		}

		/// <summary>
		/// Saves the configuration.
		/// </summary>
		private Boolean saveConfiguration()
		{
			this.MainForm.SaveHintVisible = true;
			this.MainForm.Enabled = false;
			try
			{
#if !DEBUG
				// validate,
				this.backupConfig.Validate();
#endif
				this.MainForm.ErrorGridVisible = false;
				// save
				this.backupConfig.CurrentConfiguration.Save(ConfigurationSaveMode.Modified);
				Logging.WriteInformation("configuration was saved successfully");
				// and reload
				this.loadConfig();

				if (this.showSaveHint)
				{
					MessageBoxHandler.ShowInfoMessageBox(Resources.SaveHintRestartService);
					this.showSaveHint = false;
				}

				return true;
			}
			catch (ValidationException vEx)
			{
				Logging.WriteWarning("configuration is invalid");
				this.MainForm.ErrorGridVisible = true;
				this.MainForm.ErrorItemsBindingSource.DataSource = vEx.GetErrorMessages();
				return false;
			}
			catch (Exception ex)
			{
				Logging.WriteWarning(Resources.ErrorSaveConfiguration, ex.Message, ex.StackTrace);
				MessageBoxHandler.ShowErrorMessageBox(Resources.ErrorSaveConfiguration, ex.Message, ex.StackTrace);
				return false;
			}
			finally
			{
				this.MainForm.Enabled = true;
				this.MainForm.SaveHintVisible = false;
			}
		}

		/// <summary>
		/// Gets the state of the service.
		/// </summary>
		/// <returns></returns>
		private void showServiceState()
		{
			if (this.MainForm == null) { return; }

			try
			{
				var serviceState = Resources.ServiceStateUnknown;
				var buttonEnabled = false;
				var buttonText = Resources.ServiceButtonStart;
				if (this.serviceController != null)
				{
					serviceState = Resources.ResourceManager.GetString(String.Format("ServiceState{0}", this.serviceController.Status));
					buttonText = this.serviceController.Status == ServiceControllerStatus.Running ? Resources.ServiceButtonRestart : Resources.ServiceButtonStart;
					buttonEnabled = true;
				}

				this.MainForm.SetServiceState(buttonEnabled, String.Format(Resources.ServiceStateLabelText, serviceState), buttonText);
			}
			catch (Exception ex)
			{
				Logging.WriteWarning("Error while getting service state: {0}\n{1}", ex.Message, ex.StackTrace);
			}
		}

		/// <summary>
		/// Toggles the service.
		/// </summary>
		private void toggleService()
		{
			if (this.serviceController == null) { return; }
			try
			{
				var expectedStatus = ServiceControllerStatus.Running;
				if (this.serviceController.Status == ServiceControllerStatus.Stopped)
				{
					Logging.WriteInformation("try to start service");
					this.serviceController.Start();

				}
				if (this.serviceController.Status == ServiceControllerStatus.Running)
				{
					Logging.WriteInformation("try to restart service");
					expectedStatus = ServiceControllerStatus.Stopped;
					this.MainForm.SetServiceState(false, String.Format(Resources.ServiceStateLabelText, Resources.ServiceStateStopPending), Resources.ServiceButtonRestart);
					this.serviceController.Stop();
					this.serviceController.WaitForStatus(expectedStatus, TimeSpan.FromSeconds(10));
					expectedStatus = ServiceControllerStatus.Running;
					this.MainForm.SetServiceState(false, String.Format(Resources.ServiceStateLabelText, Resources.ServiceStateStartPending), Resources.ServiceButtonRestart);
					this.serviceController.Start();
				}
				this.serviceController.WaitForStatus(expectedStatus, TimeSpan.FromSeconds(10));
			}
			catch (Exception ex)
			{
				Logging.WriteError("error while toggling servie: {0}\n{1}", ex.Message, ex.StackTrace);
			}
			this.showServiceState();
		}

		/// <summary>
		/// Trees the view after select.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Forms.TreeViewEventArgs"/> instance containing the event data.</param>
		private void treeViewAfterSelect(Object sender, TreeViewEventArgs e)
		{
			if (this.MainForm == null) { return; }

			this.MainForm.JobDetailProperties.SelectedObject = e.Node.Tag;
			var element = e.Node.Tag as CustomConfigurationElement;
			if (element != null) { element.PropertyChanged += (s, ev) => this.MainForm.JobTreeView.SelectedNode.Text = element.Name; }
		}

		#endregion Methods
	}
}